package cn.android666.nopreviewcamera

import android.opengl.GLES20
import android.opengl.GLSurfaceView
import timber.log.Timber
import java.nio.ByteBuffer
import java.nio.ByteOrder
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10

/**
 * OpenGL 渲染器
 *
 * 将YUV数据用OpenGL ES 2.0显示到界面的整体思路如下：
 *
 * 1、将 NV21 的 Y 分量和 UV 分量提取出来。
 * 2、将 Y 分量作为灰度纹理上传。
 * 3、将 UV 分量作为 GL_LUMINANCE_ALPHA 纹理上传。
 * 4、在 fragment shader 中做 YUV ➜ RGB 的颜色转换。
 * 5、使用 OpenGL ES 显示到界面。
 */
class YuvRenderer : GLSurfaceView.Renderer {
    // OpenGL 纹理 ID
    private var yTextureId = 0
    private var uvTextureId = 0
    private var program = 0

    // 当前帧的宽高
    private var frameWidth = 0
    private var frameHeight = 0

    // Y 分量和 UV 分量的数据缓冲区
    private var yBuffer: ByteBuffer? = null
    private var uvBuffer: ByteBuffer? = null

    /** 顶点着色器代码 */
    private val vertexShaderCode = """
        attribute vec4 aPosition; // 顶点位置
        attribute vec2 aTexCoord; // 纹理坐标
        varying vec2 vTexCoord;   // 传递给片元着色器
        void main() {
            gl_Position = aPosition;
            vTexCoord = aTexCoord;
        }
    """.trimIndent()

    /** 片元着色器代码 */
    private val fragmentShaderCode = """
        precision mediump float;
        varying vec2 vTexCoord;
        uniform sampler2D yTexture;
        uniform sampler2D uvTexture;

        void main() {
            float y = texture2D(yTexture, vTexCoord).r;   // Y分量
            vec2 uv = texture2D(uvTexture, vTexCoord).ra; // VU分量
            float v = uv.x - 0.5; // 如果是NV21用uv.x，如果是NV12用uv.y
            float u = uv.y - 0.5; // 如果是NV21用uv.y，如果是NV12用uv.x

            // YUV 转 RGB
            float r = y + 1.403 * v;
            float g = y - 0.344 * u - 0.714 * v;
            float b = y + 1.770 * u;
            gl_FragColor = vec4(r, g, b, 1.0);
        }
    """.trimIndent()

    private var degree = 0

    fun setCameraRotation(degree: Int) {
        this.degree = degree
    }

    override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
        val renderer = gl?.glGetString(GL10.GL_RENDERER) // 输出 GPU 型号
        Timber.i("GPU: $renderer") // 例如 "Adreno 630" 或 "Mali-G71"

        // 设置清除颜色为黑色
        GLES20.glClearColor(0f, 0f, 0f, 1f)

        // 创建并链接 shader 程序
        program = createProgram(vertexShaderCode, fragmentShaderCode)

        // 创建两个纹理：Y 和 UV
        yTextureId = createTexture()
        uvTextureId = createTexture()
    }

    override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
        // 设置 OpenGL 视口为全屏
        GLES20.glViewport(0, 0, width, height)
    }

    /** 这个函数不是运行到main线程的，它的线程名大概为：GLThread 10201 */
    override fun onDrawFrame(gl: GL10?) {
        val start = System.currentTimeMillis()
        // 清屏
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)

        // 没有有效数据就跳过渲染
        if (frameWidth == 0 || frameHeight == 0 || yBuffer == null || uvBuffer == null) return

        // 使用编译好的 shader 程序
        GLES20.glUseProgram(program)

        val s = System.currentTimeMillis()
        // 上传 Y 分量到纹理 0
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yTextureId)
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, frameWidth, frameHeight, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, yBuffer)

        // 上传 UV 分量到纹理 1（注意：是 VU 顺序）
        GLES20.glActiveTexture(GLES20.GL_TEXTURE1)
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, uvTextureId)
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE_ALPHA, frameWidth / 2, frameHeight / 2, 0, GLES20.GL_LUMINANCE_ALPHA, GLES20.GL_UNSIGNED_BYTE, uvBuffer)
        Timber.i("上传纹理耗时：${System.currentTimeMillis() - s}")

        // 绘制全屏矩形
        drawQuad(program)
        Timber.i("${Thread.currentThread().name}, onDrawFrame耗时：${System.currentTimeMillis() - start}")
    }

    /** 更新一帧的 NV21 数据（Y + VU） */
    fun updateFrame(nv21: ByteArray, width: Int, height: Int) {
        val start = System.currentTimeMillis()
        frameWidth = width
        frameHeight = height

        val ySize = width * height
        val uvSize = width * height / 2

        // 分配缓冲区（如果还没分配或大小变化）
        if (yBuffer == null || yBuffer!!.capacity() != ySize)
            yBuffer = ByteBuffer.allocateDirect(ySize)
        if (uvBuffer == null || uvBuffer!!.capacity() != uvSize)
            uvBuffer = ByteBuffer.allocateDirect(uvSize)

        // 填充 Y 缓冲区
        yBuffer!!.clear()
        yBuffer!!.put(nv21, 0, ySize)
        yBuffer!!.position(0)

        // 填充 UV 缓冲区（NV21 是交错的 VU）
        uvBuffer!!.clear()
        uvBuffer!!.put(nv21, ySize, uvSize)
        uvBuffer!!.position(0)
        Timber.i("yuv分离耗时：${System.currentTimeMillis() - start}")
    }

    /** 创建一个 2D 纹理对象并设置基本参数 */
    fun createTexture(): Int {
        val textureIds = IntArray(1)
        GLES20.glGenTextures(1, textureIds, 0)
        val texId = textureIds[0]
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texId)
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR)
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR)
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE)
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE)
        return texId
    }

    /** 编译 shader 并链接生成 program */
    fun createProgram(vertexSource: String, fragmentSource: String): Int {
        val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource)
        val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource)

        val program = GLES20.glCreateProgram()
        GLES20.glAttachShader(program, vertexShader)
        GLES20.glAttachShader(program, fragmentShader)
        GLES20.glLinkProgram(program)

        // 检查链接状态
        val linkStatus = IntArray(1)
        GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0)
        if (linkStatus[0] == 0) {
            val error = GLES20.glGetProgramInfoLog(program)
            GLES20.glDeleteProgram(program)
            throw RuntimeException("Program link failed: $error")
        }
        return program
    }

    /** 加载并编译单个 shader（顶点或片元） */
    fun loadShader(type: Int, shaderSource: String): Int {
        val shader = GLES20.glCreateShader(type)
        GLES20.glShaderSource(shader, shaderSource)
        GLES20.glCompileShader(shader)

        // 检查编译状态
        val compiled = IntArray(1)
        GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0)
        if (compiled[0] == 0) {
            val error = GLES20.glGetShaderInfoLog(shader)
            GLES20.glDeleteShader(shader)
            throw RuntimeException("Shader compile failed: $error")
        }
        return shader
    }

    /** 绘制一个矩形（全屏四顶点）用于显示纹理 */
    fun drawQuad(program: Int) {
        val aPosition = GLES20.glGetAttribLocation(program, "aPosition")
        val aTexCoord = GLES20.glGetAttribLocation(program, "aTexCoord")
        val ySampler = GLES20.glGetUniformLocation(program, "yTexture")
        val uvSampler = GLES20.glGetUniformLocation(program, "uvTexture")

        // 顶点坐标 [-1, 1]，代表全屏
        /*val vertexCoords = floatArrayOf(
            -1f, -1f,   1f, -1f,
            -1f,  1f,   1f,  1f
        )*/

        // 纹理坐标 [0, 1]
        /*val texCoords = floatArrayOf(
            0f, 1f,   1f, 1f,
            0f, 0f,   1f, 0f
        )*/

        // 修改顶点坐标实现90度旋转
        val vertexCoords = when (degree) {
            90 -> floatArrayOf(
                -1f, -1f,   -1f, 1f,
                1f, -1f,    1f, 1f
            )
            180 -> floatArrayOf(
                -1f,  1f,   1f,  1f,
                -1f, -1f,   1f, -1f
            )
            270 -> floatArrayOf(
                1f,  1f,   -1f, 1f,
                1f, -1f,   -1f, -1f
            )
            else -> floatArrayOf(
                -1f, -1f,   1f, -1f,
                -1f,  1f,   1f,  1f
            )
        }

        // 同时调整纹理坐标以匹配旋转
        val texCoords = when (degree) {
            90 -> floatArrayOf(
                1f, 1f,   0f, 1f,
                1f, 0f,   0f, 0f
            )
            180 -> floatArrayOf(
                1f, 0f,   0f, 0f,
                1f, 1f,   0f, 1f
            )
            270 -> floatArrayOf(
                0f, 0f,   1f, 0f,
                0f, 1f,   1f, 1f
            )
            else -> floatArrayOf(
                0f, 1f,   1f, 1f,
                0f, 0f,   1f, 0f
            )
        }

        val vb = ByteBuffer.allocateDirect(vertexCoords.size * 4).order(ByteOrder.nativeOrder()).asFloatBuffer()
        vb.put(vertexCoords).position(0)

        val tb = ByteBuffer.allocateDirect(texCoords.size * 4).order(ByteOrder.nativeOrder()).asFloatBuffer()
        tb.put(texCoords).position(0)

        GLES20.glEnableVertexAttribArray(aPosition)
        GLES20.glVertexAttribPointer(aPosition, 2, GLES20.GL_FLOAT, false, 0, vb)

        GLES20.glEnableVertexAttribArray(aTexCoord)
        GLES20.glVertexAttribPointer(aTexCoord, 2, GLES20.GL_FLOAT, false, 0, tb)

        // 设置纹理采样器对应的纹理单元
        GLES20.glUniform1i(ySampler, 0)  // GL_TEXTURE0
        GLES20.glUniform1i(uvSampler, 1) // GL_TEXTURE1

        // 绘制两个三角形构成的矩形（GL_TRIANGLE_STRIP）
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4)

        GLES20.glDisableVertexAttribArray(aPosition)
        GLES20.glDisableVertexAttribArray(aTexCoord)
    }

}
